home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / bit / src / gl_util.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  29KB  |  1,371 lines

  1. /*
  2.  * $Id: gl_util.c,v 0.91 1994/02/20 00:52:58 zhao Pre-Release $
  3.  *
  4.  *. This file is part of BIT shareware package. After the two weeks of
  5.  *  free evaluation period, you are encouraged (required) to register
  6.  *  your copy for a small registration fee, which is $35 for personal use
  7.  *  and $50 for commercial, government and institutional use.
  8.  *
  9.  *  Copyright(c) 1993, 1994 by T.C. Zhao.
  10.  *  All rights reserved.
  11.  *
  12.  *  Permission to use, copy, and distribute this software in its entirety
  13.  *  for non-commercial purposes is hereby granted, provided that the
  14.  *  above shareware and copyright notices and this permission notice
  15.  *  appear in all copies and their documentation.
  16.  *
  17.  *  This software may be modified for your own use, but modified versions
  18.  *  may not be distributed without prior consent of the author.
  19.  *
  20.  *  This software is provided "as is" without expressed or implied
  21.  *  warranty of any kind.
  22.  *
  23.  *.
  24.  *
  25.  *  Low level user routines (one level higher than GL primitives) dealing
  26.  *  with frame buffer switching, mouse, cursor and  rubber objects.
  27.  *
  28.  */
  29. #if !defined(lint) && defined(F_ID)
  30. char *id_glu = "$Id: gl_util.c,v 0.91 1994/02/20 00:52:58 zhao Pre-Release $";
  31. #endif
  32.  
  33. #include <stdio.h>
  34. #include <stdlib.h>
  35. #include "gl/gl.h"
  36. #include "gl/device.h"
  37. #include "gluproto.h"
  38.  
  39. extern void set_current_window(long);
  40.  
  41. /*****************************************************************
  42.  * Before any routine can be used, glu_init() must be called.
  43.  * It will in turn call init_cursor and init_overlay to do the
  44.  * job
  45.  *******************************************************************/
  46.  
  47. static void init_overlay(void);
  48.  
  49. void
  50. glu_init(void)
  51. {
  52.     static int init;
  53.  
  54.     if (!init)
  55.       {
  56.       init_cursor();
  57.       init_overlay();
  58.       init = 1;
  59.       }
  60. }
  61.  
  62. /*****************************************************************
  63.  * Simple Mouse routines
  64.  *  get_mouse(int *x, int *y);  -- get mouse position
  65.  *  set_mouse(int x, int y);    -- warp mouse to (x,y)
  66.  *  set_mouse_bounds()     ;    -- restrict movement of mouse
  67.  *  reset_mouse_bounds()   ;    -- lift the restriction
  68.  *  get_mouse_r2w(int *, int *);-- get mouse postion relative window
  69.  *****************************************************************/
  70.  
  71. #ifndef GET_MOUSE
  72. #define GET_MOUSE(x,y)             (x)= getvaluator(MOUSEX);\
  73.                                    (y)= getvaluator(MOUSEY)
  74. #define SET_MOUSE(x,y,xi,xf,yi,yf) setvaluator(MOUSEX,(x),(xi),(xf));\
  75.                                    setvaluator(MOUSEY,(y),(yi),(yf))
  76. #endif
  77.  
  78. static int mxi, myi;        /* lower bounds  */
  79. static int mxf = XMAXSCREEN;    /* X upper bounds */
  80. static int myf = YMAXSCREEN;    /* Y upper bounds */
  81.  
  82. /***************************************************************
  83.  * Free mouse from any constraints, i.e., allow free movement
  84.  * of mouse
  85.  ***************************************************************/
  86. void
  87. reset_mouse_bounds(void)
  88. {
  89.     int x, y;
  90.  
  91.     GET_MOUSE(x, y);
  92.     SET_MOUSE(x, y, (mxi = 0), (mxf = getgdesc(GD_XPMAX)),
  93.           (myi = 0), (myf = getgdesc(GD_YPMAX)));
  94. }
  95.  
  96. /* **************************************************************
  97.  * return current mouse position, relative to screen
  98.  ****************************************************************/
  99. void
  100. get_mouse(int *x, int *y)
  101. {
  102.     GET_MOUSE(*x, *y);
  103. }
  104.  
  105. /*************************************************************
  106.  * move mouse to a specific location
  107.  *************************************************************/
  108. void
  109. set_mouse(int x, int y)
  110. {
  111.     SET_MOUSE(x, y, mxi, mxf, myi, myf);
  112. }
  113.  
  114. /****************************************************************
  115.  * set restrictions on mouse
  116.  ****************************************************************/
  117. void
  118. set_mouse_bounds(int xmin, int ymin, int xmax, int ymax)
  119. {
  120.     int x, y;
  121.  
  122.     GET_MOUSE(x, y);
  123.     SET_MOUSE(x, y, (mxi = xmin), (mxf = xmax), (myi = ymin), (myf = ymax));
  124. }
  125.  
  126. /************************************************************
  127.  * similar to get_mouse, except coordinates are relative to window
  128.  ***************************************************************/
  129. void
  130. get_mouse_r2w(int *x, int *y)
  131. {
  132.     long xori, yori;
  133.  
  134.     getorigin(&xori, &yori);
  135.     get_mouse(x, y);
  136.     *x -= xori;
  137.     *y -= yori;
  138. }
  139.  
  140. /**************************************************************
  141.  * Simple overlay routines: If hardware overlay is not avaialble,
  142.  * PUPDRAW will be used as XOR drawing is not supported on all
  143.  * platforms or OSes. The upshot of this is that drawmode(OVERDRAW)
  144.  * should not be used, use switch_frame_buffer instead, which
  145.  * will do the right thing
  146.  **************************************************************/
  147.  
  148. #define  MAX_OVER 2        /* valid values are 2,4,8 */
  149.  
  150. /* default colors in overlay */
  151. static int overrgb[][3] =
  152. {
  153.     {0, 0, 0},            /* none                    */
  154.     {255, 0, 0},        /* red                     */
  155.     {0, 255, 0},        /* green                   */
  156.     {255, 255, 0}        /* yellow. blue is too dark */
  157. };
  158.  
  159. int over_pup_colors;        /* global, how many colors we got */
  160. extern int force_pupdraw;    /* undocumented */
  161.  
  162. static long otherfb;        /* hardwhere supported non regular FB */
  163.  
  164. /***************************************************************
  165.  * check if overlay exists and in case it doesn't, pupdraw will be
  166.  * used
  167.  ***************************************************************/
  168. static void
  169. init_overlay(void)
  170. {
  171.     long over_plane, pup_plane, pup_colors, overlay_colors = 0;
  172.     int i;
  173.     const char *func = "OverPupInit";
  174.  
  175.     over_plane = getgdesc(GD_BITS_OVER_SNG_CMODE);
  176.     M_info(func, "overlay bitplanes=%d", over_plane);
  177.  
  178.     /* force_pupdraw is undocumented */
  179.     if (!force_pupdraw && over_plane > 0)
  180.       {
  181.       /* don't be too greedy, use MAX_OVER even if more are possible */
  182.       over_plane = Min(over_plane, MAX_OVER);
  183.       overlay(over_plane);
  184.  
  185.       /* let the caller call gconfig */
  186.       /* gconfig();   */
  187.  
  188.       over_pup_colors = overlay_colors = 1 << over_plane;
  189.  
  190.       /* install colormap in overlay only, don't mess with pupdraw */
  191.       drawmode(OVERDRAW);
  192.       for (i = 0; i < overlay_colors; i++)
  193.           mapcolor(i, overrgb[i][0], overrgb[i][1], overrgb[i][2]);
  194.       drawmode(NORMALDRAW);
  195.       }
  196.  
  197.     /* check out pupdraw */
  198.     if ((pup_plane = getgdesc(GD_BITS_PUP_SNG_CMODE)) <= 0 && !over_plane)
  199.       {
  200.       M_err(func, "No Bitplanes for OVER and PUP !!");
  201.       exit(1);
  202.       }
  203.  
  204.     M_info(func, "pup bitplanes=%d", pup_plane);
  205.     pup_colors = (1 << pup_plane);
  206.  
  207.     /* the real harware framebuffer used */
  208.     otherfb = (overlay_colors > 1 ? OVERDRAW : PUPDRAW);
  209.  
  210.     if (over_pup_colors == 0)
  211.     over_pup_colors = pup_colors;
  212.  
  213.     M_info("InitOverPup", "using %d bitplanes from %s",
  214.        (otherfb == PUPDRAW) ? pup_plane : over_plane,
  215.        (otherfb == PUPDRAW) ? "Pupdraw" : "Overlay");
  216. }
  217.  
  218. /***************************************************
  219.  * switch the framebuffer to something other than normaldraw
  220.  **************************************************/
  221. void
  222. switch_frame_buffer(void)
  223. {
  224.     drawmode(otherfb);
  225.     reshapeviewport();
  226.  
  227. #ifdef MDEBUG
  228.     M_debug("SwitchFB", "Switching to %s",
  229.         (otherfb == PUPDRAW) ? "pupdraw" : "overlay");
  230. #endif
  231. }
  232.  
  233. /*********************************************************
  234.  * put graphics mode in full screen and clear the framebuffer.
  235.  * the fullscreen code MUST be sandwitch between
  236.  * pushmatrix/popmatrix, this EXTREMELY important otherwise
  237.  * the stack is screwed.
  238.  ***********************************************************/
  239. static void
  240. clear_fullscr(void)
  241. {
  242.     pushmatrix();
  243.     fullscrn();
  244.     cpack(0);
  245.     color(0);
  246.     clear();
  247.     endfullscrn();
  248.     popmatrix();
  249.     reshapeviewport();
  250. }
  251.  
  252. /****************************************************
  253.  * clear over_pup framebuffer
  254.  ****************************************************/
  255. extern long win_id;
  256. void
  257. clear_over_pup(void)
  258. {
  259.     set_current_window(win_id);
  260.     switch_frame_buffer();
  261.     clear_fullscr();
  262.     drawmode(NORMALDRAW);
  263. }
  264.  
  265. void
  266. op_mapcolor(int n, int r, int g, int b)
  267. {
  268.     switch_frame_buffer();
  269.     mapcolor(n, r, g, b);
  270.     drawmode(NORMALDRAW);
  271. }
  272.  
  273.  
  274. /***************************************************************
  275.  * Misc. routines
  276.  ***************************************************************/
  277. int
  278. double_buffer_capable(void)
  279. {
  280.     return (getgdesc(GD_BITS_NORM_DBL_RED) >= 6) &&
  281.     (getgdesc(GD_BITS_NORM_DBL_BLUE) >= 4) &&
  282.     (getgdesc(GD_BITS_NORM_DBL_CMODE) >= 8);
  283. }
  284.  
  285. int
  286. sml_capable(void)
  287. {
  288.     return (getgdesc(GD_BLEND) && getgdesc(GD_LINESMOOTH_RGB));
  289. }
  290.  
  291.  
  292. /*******************************************************************
  293.  * Some basic routines that draw simple geometric figures and
  294.  * they take x,y,w,h,f as arguments, representing center (x,y)
  295.  * and size (w, h). If f is true, then the region is closed, and it
  296.  * will be filled.
  297.  *
  298.  * All routines are responsible for the drawing only. All mapping,
  299.  * colors, framebuffer etc are the responsibilities of the  caller
  300.  ******************************************************************{*/
  301.  
  302. #define MINCODESIZE        /* for small code, maybe a little slower */
  303.  
  304. /* two choices for specifying a vertex: one is to call a function
  305.  * or alternatively use a macro. If MINCODESIZE is defined, function
  306.  * version will be used
  307.  */
  308.  
  309. #ifdef MINCODESIZE
  310. static void
  311. vvf(float x, float y)
  312. {
  313.     float xy[2];
  314.     xy[0] = x;
  315.     xy[1] = y;
  316.     v2f(xy);
  317. }
  318.  
  319. #else
  320.  
  321. #define vvf(x, y)         \
  322.     do {  float xy[2];    \
  323.        xy[0] = (x);       \
  324.        xy[1] = (y);       \
  325.        v2f(x,y);          \
  326.     } while (ZERO)
  327.  
  328. #endif
  329.  
  330. /**** draw a strightline from (xi, yi) to (xf, yf) ****/
  331. void
  332. draw_line(float xi, float yi, float xf, float yf)
  333. {
  334.     bgnline();
  335.     vvf(xi, yi);
  336.     vvf(xf, yf);
  337.     endline();
  338. }
  339.  
  340. #define  Bfill(f)   (f ? bgnpolygon: bgnclosedline)()
  341. #define  Efill(f)   (f ? endpolygon: endclosedline)()
  342.  
  343. /* ARGSUSED */
  344. void
  345. gl_line(int x, int y, int w, int h, int f, int a)
  346. {
  347.     pushmatrix();
  348.     translate(x, y, 0);
  349.     rotate(a, 'z');
  350.     scale((float) w, (float) h, 1.0);
  351.     draw_line(-0.5, 0.0, 0.5, 0.0);
  352.     popmatrix();
  353. }
  354.  
  355. /**************** square, rectangle ********************/
  356. void
  357. gl_rect(int x, int y, int w, int h, int fill, int a)
  358. {
  359.     pushmatrix();
  360.     translate(x, y, 0);
  361.     rotate(a, 'z');
  362.     scale((float) w, (float) h, 1.0);
  363.     (fill ? rectf : rect) (-0.5, -0.5, 0.5, 0.5);
  364.     popmatrix();
  365. }
  366.  
  367. /*************  circle, eliipse ************/
  368. /* ARGSUSED */
  369. void
  370. gl_circ(int x, int y, int w, int h, int fill, int a)
  371. {
  372.     pushmatrix();
  373.     translate(x, y, 0);
  374.     rotate(a, 'z');
  375.     scale((float) w, (float) h, 1);
  376.     (fill ? circf : circ) (0, 0, 0.5);
  377.     popmatrix();
  378. }
  379.  
  380. /************** draw a star ****************/
  381. #include <math.h>
  382. void
  383. gl_star(int x, int y, int w, int h, int f, int a)
  384. {
  385.     static int first = 1;
  386.     static float xy[10][2];
  387.     int i;
  388.  
  389.     /* generate the unit star on the fly first time */
  390.     if (first)
  391.       {                /* calculate  coordinates */
  392.       float t;
  393.       float a2r = (acos(-1.0) / 180.0);
  394.       float l = (sin(18.0 * a2r) / sin(54.0 * a2r));
  395.  
  396.       first = 0;
  397.       for (i = 0, t = 54.0; i < 10; i += 2, t += 72.0)
  398.         {
  399.         xy[i][0] = l * cos(t * a2r);
  400.         xy[i][1] = l * sin(t * a2r);
  401.         }
  402.       for (i = 1, t = 90.0; i < 10; i += 2, t += 72.0)
  403.         {
  404.         xy[i][0] = cos(t * a2r);
  405.         xy[i][1] = sin(t * a2r);
  406.         }
  407.       }
  408.     /* drw it */
  409.     pushmatrix();
  410.     translate(x, y, 0);
  411.     rotate(a, 'z');
  412.     scale(0.5 * w, 0.5 * h, 1.0);
  413.     Bfill(f);
  414.     for (i = 0; i < 10; i++)
  415.     v2f(xy[i]);
  416.     Efill(f);
  417.     popmatrix();
  418. }
  419.  
  420. /***************** an arrow. *******************/
  421. void
  422. gl_arrow(int x, int y, int w, int h, int f, int a)
  423. {
  424.     float aw = 0.1, al = 0.7;    /* arrow width and length */
  425.  
  426.     pushmatrix();
  427.     translate(x, y, 0);
  428.     rotate(a, 'z');
  429.     scale(0.5 * w, 0.5 * h, 1.0);
  430.     draw_line(-1.0, 0.0, al, 0.0);
  431.     Bfill(f);
  432.     vvf(al, aw);
  433.     vvf(al, -aw);
  434.     vvf(1.0, 0.0);
  435.     Efill(f);
  436.     popmatrix();
  437. }
  438.  
  439. /***********  triangle, nabla ***********/
  440. void
  441. gl_tri(int x, int y, int w, int h, int fill, int a)
  442. {
  443.     pushmatrix();
  444.     translate(x, y, 0);
  445.     scale((float) w, (float) h, 1);
  446.     rotate(a, 'z');
  447.  
  448.     Bfill(fill);
  449.     vvf(0.5, -0.5);
  450.     vvf(0, 0.5);
  451.     vvf(-0.5, -0.5);
  452.     Efill(fill);
  453.     popmatrix();
  454. }
  455.  
  456. /* ARGSUSED */
  457. static void
  458. draw_cross(int x, int y, int w, int h, int fill, int a)
  459. {
  460.     draw_line(x - w * 0.5, y - h * 0.5, x + w * 0.5, y + h * 0.5);
  461.     draw_line(x - w * 0.5, y + h * 0.5, x + w * 0.5, y - h * 0.5);
  462. }
  463.  
  464. /*************** cross, times **********/
  465. /* ARGSUSED */
  466. void
  467. gl_plus(int x, int y, int w, int h, int fill, int a)
  468. {
  469.     pushmatrix();
  470.     translate(x, y, 0);
  471.     scale(0.5 * w, 0.5 * h, 1.0);
  472.     rotate(a, 'z');
  473.     draw_line(0.0, -1.0, 0.0, 1.0);
  474.     draw_line(-1.0, 0.0, 1.0, 0.0);
  475.     popmatrix();
  476. }
  477.  
  478. /***** |----| ********************/
  479. /* ARGSUSED */
  480. void
  481. gl_hdist(int x, int y, int w, int h, int fill, int a)
  482. {
  483.     pushmatrix();
  484.     translate(x, y, 0);
  485.     rotate(a, 'z');
  486.     scale((float) w, (float) h, 1.0);
  487.     draw_line(-0.5, 0, 0.5, 0);
  488.     draw_line(-0.5, -0.12, -0.5, 0.12);
  489.     draw_line(0.5, -0.12, 0.5, 0.12);
  490.     popmatrix();
  491. }
  492. /* End of simple geometric figure routines } */
  493.  
  494. /**************************************************************
  495.  * Routines that deal with rubber objects
  496.  * winget and winget are reduced to a minimum and calling
  497.  * routine probably should take care some of them
  498.  ***************************************************************/
  499.  
  500. /***********************************************************
  501.  * Basic drawing routines: void (*draw) (int, int, int, int);
  502.  ***********************************************************/
  503.  
  504. typedef void (*Drawobj) (int, int, int, int);
  505.  
  506. /***** draw a circle at (x,y) with radius = w/2; ****/
  507. static void
  508. rb_circ(int x, int y, int w, int h)
  509. {
  510.     int radius = Min(w, h) / 2;
  511.     circi(x + radius, y + radius, radius);
  512. }
  513.  
  514. /**********
  515.   draw line from (x,y) to (x+w-1, y+h-1) and mark origin with a circle
  516.  */
  517. static void
  518. rb_line(int x, int y, int w, int h)
  519. {
  520.     long v1[2], v2[2];
  521.  
  522.     v1[0] = x;
  523.     v1[1] = y;
  524.     v2[0] = x + w - 1;
  525.     v2[1] = y + h - 1;
  526.     bgnline();
  527.     v2i(v1);
  528.     v2i(v2);
  529.     endline();
  530.     circi(x, y, 10);
  531. }
  532.  
  533. /***** draw a rectangle ****/
  534. static void
  535. rb_rect(int x, int y, int w, int h)
  536. {
  537.     recti(x, y, x + w - 1, y + h - 1);
  538. }
  539.  
  540. static int lastx, lasty, lastw, lasth, lastcr;
  541. static int check, xmin, ymin, width, height, onscrn, lastc;
  542. static long lastwin;
  543. static int center, obj;
  544.  
  545. /**********************************************************
  546.  * make sure the object stays within bounds
  547.  * width and height are given highier priority than localtions
  548.  *********************************************************/
  549. static void
  550. check_rect_bounds(int *x, int *y, int *w, int *h)
  551. {
  552.     if (*w < 0)
  553.       {
  554.       *w = -*w;
  555.       *x -= *w;
  556.       }
  557.     if (*h < 0)
  558.       {
  559.       *h = -*h;
  560.       *y -= *h;
  561.       }
  562.     if (*w > width)
  563.     *w = width;
  564.     if (*h > height)
  565.     *h = height;
  566.  
  567.     if (*x < xmin)
  568.     *x = xmin;
  569.     if (*y < ymin)
  570.     *y = ymin;
  571.  
  572.     if (*x + *w > xmin + width)
  573.     *x = xmin + width - *w;
  574.     if (*y + *h > ymin + height)
  575.     *y = ymin + height - *h;
  576. }
  577.  
  578. static void
  579. check_circ_bounds(int *x, int *y, int *w, int *h)
  580. {
  581.     int maxdia = Min(width, height);
  582.  
  583.     if (*w < 0)
  584.       {
  585.       *w = -*w;
  586.       *x -= *w;
  587.       }
  588.     if (*h < 0)
  589.       {
  590.       *h = -*h;
  591.       *y -= *h;
  592.       }
  593.     if (*w > maxdia)
  594.     *w = maxdia;
  595.     *h = *w;
  596.  
  597.     if (*x < xmin)
  598.     *x = xmin;
  599.     if (*y < ymin)
  600.     *y = ymin;
  601.  
  602.     if (*x + *w > xmin + width)
  603.     *x = xmin + width - *w;
  604.     if (*y + *h > ymin + height)
  605.     *y = ymin + height - *h;
  606. }
  607.  
  608. /* width and height can be nagative for lines */
  609. static void
  610. check_line_bounds(int *x, int *y, int *w, int *h)
  611. {
  612.     if (Abs(*w) > width)
  613.     *w = (*w / Abs(*w)) * width;
  614.     if (Abs(*h) > height)
  615.     *h = (*h / Abs(*h)) * height;
  616.  
  617.     if (*x < xmin)
  618.     *x = xmin;
  619.     if (*x > xmin + width)
  620.     *x = xmin + width;
  621.     if (*x + *w < xmin)
  622.     *x = xmin - *w;
  623.     if (*x + *w > xmin + width)
  624.     *x = xmin + width - *w;
  625.  
  626.     if (*y < ymin)
  627.     *y = ymin;
  628.     if (*y > ymin + height)
  629.     *y = ymin + height;
  630.     if (*y + *h < ymin)
  631.     *y = ymin - *h;
  632.     if (*y + *h > ymin + height)
  633.     *y = ymin + height - *h;
  634. }
  635.  
  636.  
  637. /***********************************************
  638.  * All rubber objects must have XX_new, XX_hide
  639.  ************************************************/
  640. /* set the rubber color */
  641. static void
  642. rb_color(int c)
  643. {
  644.     switch_frame_buffer();
  645.     c %= over_pup_colors;
  646.     color((lastc = c));
  647.     drawmode(NORMALDRAW);
  648. }
  649.  
  650. /* put up a new rubber. All coordinates are assumed to be ok */
  651. static void
  652. rb_new(int x, int y, int w, int h, Drawobj drawit)
  653. {
  654.     int q = (obj == RB_LINE) ? 1 : 2;    /* interior size */
  655.  
  656.     switch_frame_buffer();
  657.     reshapeviewport();
  658.     color(lastc);
  659.     if (lastcr > 0)
  660.       {
  661.       draw_cross(x, y, lastcr, lastcr, 0, 0);
  662.       draw_cross(x + w - 1, y + h - 1, lastcr, lastcr, 0, 0);
  663.       }
  664.     lastx = x;
  665.     lasty = y;
  666.     lastw = w;
  667.     lasth = h;
  668.     drawit(x, y, w, h);
  669.     drawmode(NORMALDRAW);
  670.     onscrn = 1;
  671.  
  672.     /*
  673.      * show interior size of the rectangle. In case of line, there is no
  674.      * interior size to talk about. Reports theta
  675.      */
  676.  
  677.     show_rect_all(x, y, w - q, h - q, q == 1);
  678.     return;
  679. }
  680.  
  681. /* erase last rubber */
  682. static void
  683. rb_hide(Drawobj drawit)
  684. {
  685.     if (!onscrn)
  686.     return;
  687.     switch_frame_buffer();
  688.     reshapeviewport();
  689.     color(0);
  690.     if (lastcr > 0)
  691.       {
  692.       draw_cross(lastx, lasty, lastcr, lastcr, 0, 0);
  693.       draw_cross(lastx + lastw - 1, lasty + lasth - 1,
  694.              lastcr, lastcr, 0, 0);
  695.       }
  696.     drawit(lastx, lasty, lastw, lasth);
  697.     drawmode(NORMALDRAW);
  698.     onscrn = 0;
  699.     return;
  700. }
  701.  
  702. /*****************************************************
  703.  * Now some high level user routines
  704.  ****************************************************/
  705. #include "forms.h"        /* for qtest etc */
  706.  
  707. typedef void (*Ckbounds) (int *, int *, int *, int *);
  708.  
  709. typedef struct
  710.   {
  711.       int obj;
  712.       Drawobj drawit;
  713.       Ckbounds checkb;
  714.   }
  715. Draw;
  716.  
  717. static Draw drawobj[] =
  718. {
  719.     {RB_RECT, rb_rect, check_rect_bounds},
  720.     {RB_CIRC, rb_circ, check_circ_bounds},
  721.     {RB_LINE, rb_line, check_line_bounds}
  722. };
  723.  
  724. static Draw *p = drawobj;
  725. static int maxobjs = sizeof(drawobj) / sizeof(Draw);
  726.  
  727. /* if set, rubber will center at (x,y) */
  728. void
  729. set_rubber_center(int ctr)
  730. {
  731.     center = ctr;
  732. }
  733.  
  734. /* if there is any rubber on screen */
  735. int
  736. rubber_on_screen(long *win, int *c)
  737. {
  738.     *win = lastwin;
  739.     *c = lastc;
  740.     return onscrn;
  741. }
  742.  
  743. /* set the rubber bounds. ck==0 disables checking */
  744. void
  745. set_rubber_bounds(int ck, int x, int y, int w, int h)
  746. {
  747.     if ((check = ck))
  748.       {
  749.       width = w;
  750.       height = h;
  751.       xmin = x;
  752.       ymin = y;
  753.       }
  754. }
  755.  
  756. /* which rubber obj to draw */
  757. void
  758. set_rubber_obj(int o)
  759. {
  760.     int i = 0;
  761.  
  762.     rb_hide(p->drawit);
  763.     for (i = 0; i < maxobjs && drawobj[i].obj != o; i++)
  764.     ;
  765.  
  766.     if (i < maxobjs)
  767.       {
  768.       obj = o;
  769.       p = &drawobj[obj];
  770.       }
  771.     /* rb_new(lastx, lasty, lastw, lasth, p->drawit); */
  772. }
  773.  
  774. int
  775. get_max_rubber_obj(void)
  776. {
  777.     return sizeof(drawobj) / sizeof(Draw);
  778. }
  779.  
  780. /* draw a new one */
  781.  
  782. /* move a rubber to the new location */
  783. void
  784. rubber_moveto(int *x, int *y, int *w, int *h)
  785. {
  786.     long owin = winget();
  787.     set_current_window(lastwin);
  788.     if (check)
  789.     p->checkb(x, y, w, h);
  790.     if (!onscrn || *x - lastx || *y - lasty || *w - lastw || *h - lasth)
  791.       {
  792.       rb_hide(p->drawit);
  793.       rb_new(*x, *y, *w, *h, p->drawit);
  794.       }
  795.     if (owin > 0)
  796.     set_current_window(owin);
  797. }
  798.  
  799. void
  800. rubber_new(long win, int x, int y, int w, int h, int c)
  801. {
  802.     set_current_window(lastwin = win);
  803.     rb_color(c);
  804.     rb_new(x, y, w, h, p->drawit);
  805. }
  806.  
  807. void
  808. rubber_show(int c)
  809. {
  810.     rb_color(c);
  811.     rb_new(lastx, lasty, lastw, lasth, p->drawit);
  812. }
  813.  
  814. void
  815. rubber_hide(void)
  816. {
  817.     rb_hide(p->drawit);
  818. }
  819.  
  820. void
  821. rubber_finish(void)
  822. {
  823.     rb_hide(p->drawit);
  824.     hide_rect_all();
  825. }
  826.  
  827. /************************************************************
  828.  * Show a rubber object that moves with the mouse.
  829.  * this routine returns whenever there is  change in the postion
  830.  * or when there is Q-event pending
  831.  *
  832.  * Note: size of the rubber object is NOT changeable, to do that
  833.  *       Use rubber_info
  834.  */
  835. long
  836. rubber_cursor(long win, short *val, int *x, int *y, int w, int h, int c)
  837. {
  838.     long xori, yori, dev = 0;
  839.     int moved;
  840.     static int lastmx, lastmy;
  841.     int mx, my;
  842.  
  843.     set_current_window(lastwin = win);
  844.     p = &drawobj[obj];
  845.     rb_color(c);
  846.     lastcr = 0;
  847.     getorigin(&xori, &yori);
  848.  
  849.     moved = 0;
  850.  
  851.     (void) fl_check_forms();
  852.     do
  853.       {
  854.       get_mouse(&mx, &my);
  855.  
  856.       /* we must let this run thru once */
  857.       if (lastmx != mx || lastmy != my)
  858.         {
  859.         lastmx = mx;
  860.         lastmy = my;
  861.         moved = 1;
  862.         *x = (mx - xori);
  863.         *y = (my - yori);
  864.         if (center)
  865.           {
  866.               *x -= w / 2;
  867.               *y -= h / 2;
  868.           }
  869.         rubber_moveto(x, y, &w, &h);
  870.         }
  871.  
  872.       if (!fl_qtest())
  873.           fl_check_forms();
  874.       else
  875.           dev = fl_qread(val);
  876.       }
  877.     while ((dev == 0 || *val == 0) && !moved);
  878.     return dev;
  879. }
  880.  
  881. /***********************************************************
  882.  * General rectangle routine:
  883.  * Both size and location can be changed by mouse or
  884.  * keyboard key i,j,k,l.
  885.  ************************************************************/
  886. static int step = 1;
  887. void
  888. set_rubber_change_rate(int a)
  889. {
  890.     if (a > 0)
  891.       {
  892.       step = a;
  893.       show_rect_speed(a);
  894.       }
  895. }
  896.  
  897. static int
  898. in_rect(int x, int y, int xi, int yi, int xsize, int ysize)
  899. {
  900.     return (Abs(xi - x) < xsize && Abs(yi - y) < ysize);
  901.  
  902. }
  903.  
  904.  
  905. /***************************************************************
  906.  * Handles ijkl, xXyY keys and numbers: return 1 if unknown
  907.  *
  908.  *  if lastcr == 0, the size will not be changable
  909.  ****************************************************************/
  910.  
  911. static int
  912. handle_keybd(int k, int *x, int *y, int *w, int *h)
  913. {
  914.     int ret = 0, l;
  915.     int xm, ym, dist1, dist2;
  916.  
  917.     get_mouse(&xm, &ym);
  918.  
  919.     dist1 = Abs((xm - *x)) + Abs(ym - *y);
  920.     dist2 = Abs(xm - (*x + *w - 1)) + Abs(ym - (*y + *h - 1));
  921.  
  922.     l = dist1 < dist2;
  923.  
  924.     switch (k)
  925.       {
  926.       case 'h':
  927.       case 'H':
  928.       if (!lastcr || control_down)
  929.         {
  930.         (*x) -= step;
  931.         }
  932.       else if (getbutton(RIGHTSHIFTKEY))
  933.         {
  934.         (*w) -= step;
  935.         }
  936.       else if (getbutton(LEFTSHIFTKEY))
  937.         {
  938.         (*x) -= step;
  939.         (*w) += step;
  940.         }
  941.       else if (l)
  942.         {
  943.         (*x) -= step;
  944.         (*w) += step;
  945.         }
  946.       else
  947.           (*w) -= step;
  948.       break;
  949.       case 'j':
  950.       case 'J':
  951.       if (!lastcr || control_down)
  952.         {
  953.         (*y) -= step;
  954.         }
  955.       else if (getbutton(RIGHTSHIFTKEY))
  956.         {
  957.         (*h) -= step;
  958.         }
  959.       else if (getbutton(LEFTSHIFTKEY))
  960.         {
  961.         (*y) -= step;
  962.         (*h) += step;
  963.         }
  964.       else if (l)
  965.         {
  966.         (*y) -= step;
  967.         (*h) += step;
  968.         }
  969.       else
  970.           (*h) -= step;
  971.       break;
  972.       case 'l':
  973.       case 'L':
  974.       if (!lastcr || control_down)
  975.         {
  976.         (*x) += step;
  977.         }
  978.       else if (getbutton(RIGHTSHIFTKEY))
  979.         {
  980.         (*w) += step;
  981.         }
  982.       else if (getbutton(LEFTSHIFTKEY))
  983.         {
  984.         (*x) += step;
  985.         (*w) -= step;
  986.         }
  987.       else if (l)
  988.         {
  989.         (*x) += step;
  990.         (*w) -= step;
  991.         }
  992.       else
  993.           (*w) += step;
  994.       break;
  995.       case 'k':
  996.       case 'K':
  997.       if (!lastcr || control_down)
  998.         {
  999.         (*y) += step;
  1000.         }
  1001.       else if (getbutton(RIGHTSHIFTKEY))
  1002.         {
  1003.         (*h) += step;
  1004.         }
  1005.       else if (getbutton(LEFTSHIFTKEY))
  1006.         {
  1007.         (*y) += step;
  1008.         (*h) -= step;
  1009.         }
  1010.       else if (l)
  1011.         {
  1012.         (*y) += step;
  1013.         (*h) -= step;
  1014.         }
  1015.       else
  1016.           (*h) += step;
  1017.       break;
  1018.       case 'x':
  1019.       if (lastcr)
  1020.         {
  1021.         *w -= 2 * step;
  1022.         *x += step;
  1023.         }
  1024.       break;
  1025.       case 'X':
  1026.       if (lastcr)
  1027.         {
  1028.         *w += 2 * step;
  1029.         *x -= step;
  1030.         }
  1031.       break;
  1032.       case 'y':
  1033.       if (lastcr)
  1034.         {
  1035.         *h -= 2 * step;
  1036.         *y += step;
  1037.         }
  1038.       break;
  1039.       case 'Y':
  1040.       if (lastcr)
  1041.         {
  1042.         *h += 2 * step;
  1043.         *y -= step;
  1044.         }
  1045.       break;
  1046.       default:
  1047.       if (k > '0' && k <= '9')
  1048.         {
  1049.         set_rubber_change_rate((k - '0'));
  1050.         }
  1051.       else
  1052.           ret = 1;
  1053.       break;
  1054.       }
  1055.     return ret;
  1056. }
  1057.  
  1058. static void (*ricb) (int, int, int, int);
  1059. void
  1060. set_rubber_info_cb(void (*fn) (int, int, int, int))
  1061. {
  1062.     ricb = fn;
  1063. }
  1064.  
  1065. static int
  1066. handle_mouse(long dev, int *x, int *y, int *w, int *h,
  1067.          int xo, int yo, int cr)
  1068. {
  1069.     int ret = 0;
  1070.     int xm, ym, oxm, oym = -1;
  1071.     int dx, dy;
  1072.     int ox = *x, oy = *y;
  1073.  
  1074.     WHERE_R2W(xm, ym, xo, yo);
  1075.  
  1076.  
  1077.     if (cr == 0)
  1078.       {
  1079.       if (in_rect(xm, ym, *x + *w / 2, *y + *h / 2, *w / 2, *h / 2))
  1080.         {
  1081.         if (ricb)
  1082.             rubber_hide();
  1083.         do
  1084.           {
  1085.               oxm = xm;
  1086.               oym = ym;
  1087.               WHERE_R2W(xm, ym, xo, yo);
  1088.               *x += xm - oxm;
  1089.               *y += ym - oym;
  1090.               if (ricb)
  1091.             {
  1092.                 ricb(ox, oy, *x, *y);
  1093.                 ox = *x;
  1094.                 oy = *y;
  1095.             }
  1096.               else
  1097.               rubber_moveto(x, y, w, h);
  1098.           }
  1099.         while (getbutton(dev));
  1100.         rubber_moveto(x, y, w, h);
  1101.         return (ox != *x || oy != *y);
  1102.         }
  1103.       return 1;
  1104.       }
  1105.  
  1106.     if (control_down)
  1107.       {
  1108.       do
  1109.         {
  1110.         oxm = xm;
  1111.         oym = ym;
  1112.         WHERE_R2W(xm, ym, xo, yo);
  1113.         *x += xm - oxm;
  1114.         *y += ym - oym;
  1115.         rubber_moveto(x, y, w, h);
  1116.         }
  1117.       while (control_down && mouse_down);
  1118.       }
  1119.     else if (in_rect(xm, ym, *x, *y, cr, cr))
  1120.       {
  1121.       do
  1122.         {
  1123.         WHERE_R2W(xm, ym, xo, yo);
  1124.         *w -= (dx = (xm - *x + 1));
  1125.         *h -= (dy = (ym - *y + 1));
  1126.         *x += dx;
  1127.         *y += dy;
  1128.         rubber_moveto(x, y, w, h);
  1129.         }
  1130.       while (mouse_down);
  1131.       }
  1132.     else if (in_rect(xm, ym, *x + *w - 1, *y + *h - 1, cr, cr))
  1133.       {
  1134.       do
  1135.         {
  1136.         WHERE_R2W(xm, ym, xo, yo);
  1137.         *w = xm - *x + 1;
  1138.         *h = ym - *y + 1;
  1139.         rubber_moveto(x, y, w, h);
  1140.         }
  1141.       while (mouse_down);
  1142.       }
  1143.     else
  1144.     ret = 1;
  1145.     return ret;
  1146. }
  1147.  
  1148.  
  1149. static void
  1150. event_wait(long win, int xo, int yo, int x, int y, int w, int h, int cr)
  1151. {
  1152.     int xm, ym, in;
  1153.  
  1154.     do
  1155.       {
  1156.       fl_check_forms();
  1157.       WHERE_R2W(xm, ym, xo, yo);
  1158.       if (cr != 0)
  1159.         {
  1160.         in = in_rect(xm, ym, x, y, cr, cr) ||
  1161.             in_rect(xm, ym, x + w - 1, y + h - 1, cr, cr);
  1162.         }
  1163.       else
  1164.         {
  1165.         in = in_rect(xm, ym, x + w / 2, y + h / 2, w / 2, h / 2);
  1166.         }
  1167.       set_cursor(win, in ? CUR_HAND : CUR_DEFAULT);
  1168.       }
  1169.     while (!fl_qtest());
  1170. }
  1171.  
  1172.  
  1173. /*
  1174.  * The ultimate rubber object. both size and location of the rubber
  1175.  * object can be changed either by mouse or keyboard. All Q events
  1176.  * are rembered and returned.
  1177.  */
  1178. long
  1179. rubber_info(long win, short *val, int *x, int *y, int *w, int *h,
  1180.         int fc, int cr)
  1181. {
  1182.     int done = 0, ock = check;
  1183.     long dev, xo, yo;
  1184.  
  1185.     p = &drawobj[obj];
  1186.     set_current_window(lastwin = win);
  1187.     reshapeviewport();
  1188.     getorigin(&xo, &yo);
  1189.  
  1190.     rb_color(fc);
  1191.     if (lastcr != cr)
  1192.       {
  1193.       lastcr = cr;
  1194.       rb_new(*x, *y, *w, *h, p->drawit);
  1195.       }
  1196.     else
  1197.       {
  1198.       rubber_moveto(x, y, w, h);
  1199.       }
  1200.     check = 0;            /* must suspend bound checking */
  1201.     set_rubber_change_rate(step);
  1202.  
  1203.     /*
  1204.      * LeftMouse and MiddleMouse will be dropped unless it does not happen on
  1205.      * the cross. Loop terminates if others events are present
  1206.      */
  1207.     do
  1208.       {
  1209.       event_wait(win, xo, yo, *x, *y, *w, *h, cr);
  1210.       switch ((dev = fl_qread(val)))
  1211.         {
  1212.         case LEFTARROWKEY:
  1213.         if (*val)
  1214.             handle_keybd('h', x, y, w, h);
  1215.         break;
  1216.         case RIGHTARROWKEY:
  1217.         if (*val)
  1218.             handle_keybd('l', x, y, w, h);
  1219.         break;
  1220.         case UPARROWKEY:
  1221.         if (*val)
  1222.             handle_keybd('k', x, y, w, h);
  1223.         break;
  1224.         case DOWNARROWKEY:
  1225.         if (*val)
  1226.             handle_keybd('j', x, y, w, h);
  1227.         break;
  1228.         case KEYBD:
  1229.         done = (*val && handle_keybd(*val, x, y, w, h));
  1230.         break;
  1231.         case INPUTCHANGE:
  1232.         if (*val > 0)
  1233.             set_current_window(*val);
  1234.         break;
  1235.         case LEFTMOUSE:
  1236.         case MIDDLEMOUSE:
  1237.         done = *val && handle_mouse(dev, x, y, w, h, xo, yo, cr);
  1238.         break;
  1239.         default:
  1240.         done = 1;
  1241.         break;
  1242.         }
  1243.       if (ock)
  1244.           p->checkb(x, y, w, h);
  1245.       rubber_moveto(x, y, w, h);
  1246.       }
  1247.     while (!done);
  1248.  
  1249.     if ((check = ock))
  1250.     p->checkb(x, y, w, h);
  1251.  
  1252.     set_cursor(win, CUR_DEFAULT);
  1253.  
  1254.     return dev;
  1255. }
  1256.  
  1257. void
  1258. end_rubber_info(void)
  1259. {
  1260.     fl_qenter(KEYBD, 20);
  1261. }
  1262.  
  1263. /**********************************************************************
  1264.  * Color Wheel
  1265.  ******************************************************************{***/
  1266. static float cw_fr[200], cw_fg[200], cw_fb[200];
  1267. static unsigned long cw_col[200];
  1268. static float cw_xy[200][2], cw_ctr[2];
  1269. static int nm, cw_max = 255;
  1270.  
  1271. #include <math.h>
  1272. #ifndef M_PI
  1273. #define M_PI cos(-1.0)
  1274. #endif
  1275.  
  1276. static void
  1277. cw_color_scale(void)
  1278. {
  1279.     static int lcw_max = -1;
  1280.  
  1281.     if (cw_max != lcw_max)
  1282.       {
  1283.       int i, r, g, b;
  1284.       for (i = 0; i < nm; i++)
  1285.         {
  1286.         r = cw_fr[i] * cw_max + 0.1;
  1287.         g = cw_fg[i] * cw_max + 0.1;
  1288.         b = cw_fb[i] * cw_max + 0.1;
  1289.         cw_col[i] = r | (g << 8) | (b << 16);
  1290.         }
  1291.       lcw_max = cw_max;
  1292.       }
  1293. }
  1294.  
  1295. static float
  1296. f_theta(double t)
  1297. {
  1298.     if (t < 0.0)
  1299.     t += 360.0;
  1300.  
  1301.     if (t <= 60.0)
  1302.     return 1;
  1303.     else if (t > 60.0 && t <= 120.0)
  1304.     return (120 - t) / 60;
  1305.     else if (t > 120 && t <= 240)
  1306.     return 0;
  1307.     if (t > 240. && t <= 300.0)
  1308.     return (t - 240.0) / 60;
  1309.     else
  1310.     return 1;
  1311. }
  1312.  
  1313. static void
  1314. gen_unit_cw(void)
  1315. {
  1316.     int i;
  1317.     double t, dt = 2.0;
  1318.     double d2r = M_PI / 180.0;
  1319.  
  1320.     if (nm != 0)
  1321.     return;
  1322.  
  1323.     /* center coordinates */
  1324.     cw_ctr[0] = cw_ctr[1] = 0;
  1325.  
  1326.     for (i = 0, t = 0.0; t <= 360.0; t += dt, i++)
  1327.       {
  1328.       cw_xy[i][0] = cos(t * d2r);
  1329.       cw_xy[i][1] = sin(t * d2r);
  1330.       cw_fr[i] = f_theta(t);
  1331.       cw_fg[i] = f_theta(t - 120.0);
  1332.       cw_fb[i] = f_theta((t - 240.0));
  1333.       }
  1334.     nm = i;
  1335. }
  1336.  
  1337. void
  1338. draw_color_wheel(int x, int y, int w, int h)
  1339. {
  1340.     int i;
  1341.  
  1342.     gen_unit_cw();
  1343.     cw_color_scale();
  1344.  
  1345.     pushmatrix();
  1346.     translate(x, y, 0);
  1347.     scale(w, h, 1);
  1348.     shademodel(GOURAUD);
  1349.  
  1350.     bgntmesh();
  1351.     cpack(cw_max | (cw_max << 8) | (cw_max << 16));
  1352.     v2f(cw_ctr);
  1353.  
  1354.     for (i = 0; i < nm; i++)
  1355.       {
  1356.       cpack(cw_col[i]);
  1357.       v2f(cw_xy[i]);
  1358.       swaptmesh();
  1359.       }
  1360.     endtmesh();
  1361.     popmatrix();
  1362. }
  1363.  
  1364. void
  1365. set_color_wheel_max(int c)
  1366. {
  1367.     cw_max = c;
  1368. }
  1369.  
  1370. /*** END of Color Wheels *****/
  1371.